// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()

/**
 * 微信小程序云支付模块封装
 */
let config = require('./config.js')
let request = require('request')
let createHash = require('create-hash')
let util = require('./util.js')
let xml = require('xml2js')

/**
 * 生成预支付的签名
 * @param appid 小程序ID（应用的id）
 * @param attach 附加数据
 * @param body 支付主体内容
 * @param openid 用户的openid
 * @param total_fee 支付总金额
 * @param notify_url 通知地址：异步接收微信支付结果通知的回调地址，通知url必须为外网访问的url，不能携带参数
 * @param ip 本机ip地址
 * @param nonce_str 随机数
 * @param out_trade_no 生成系统的交易订单号
 * @returns {string}
 */
let getPrePaySign = function (appid, attach, body, openid, total_fee, notify_url, ip, nonce_str, out_trade_no) {
    let params = {
        appid,
        attach,
        body,
        mch_id: config.mch_id,
        nonce_str,
        notify_url,
        openid,
        out_trade_no,
        total_fee,
        trade_type: 'JSAPI'
    }
    let string = util.raw(params) + '&key=' + config.key
    let sign = createHash('md5').update(string).digest('hex')
    return sign.toUpperCase()
}

/**
 * 签名成功后，根据参数拼接组装XML格式的数据，调用下单接口
 * @param appid 小程序ID（应用的id）
 * @param attach 附加数据
 * @param body 支付主体内容
 * @param openid 用户的openid
 * @param total_fee 支付总金额
 * @param notify_url 通知地址：异步接收微信支付结果通知的回调地址，通知url必须为外网访问的url，不能携带参数
 * @param ip 本机ip地址
 * @param nonce_str 随机数
 * @param out_trade_no 生成系统的交易订单号
 * @param sign 支付签名
 * @returns {string}
 */
let wxSendData = function (appid, attach, body, openid, total_fee, notify_url, ip, nonce_str, out_trade_no, sign) {
    let data = '<xml>' +
        '<appid><![CDATA[' + appid + ']]></appid>' +
        '<attach><![CDATA[' + attach + ']]></attach>' +
        '<body><![CDATA[' + body + ']]></body>' +
        '<mch_id><![CDATA[' + config.mch_id + ']]></mch_id>' +
        '<nonce_str><![CDATA[' + nonce_str + ']]></nonce_str>' +
        '<notify_url><![CDATA[' + notify_url + ']]></notify_url>' +
        '<openid><![CDATA[' + openid + ']]></openid>' +
        '<out_trade_no><![CDATA[' + out_trade_no + ']]></out_trade_no>' +
        '<spbill_create_ip><![CDATA[' + ip + ']]></spbill_create_ip>' +
        '<total_fee><![CDATA[' + total_fee + ']]></total_fee>' +
        '<trade_type><![CDATA[JSAPI]]></trade_type>' +
        '<sign><![CDATA[' + sign + ']]></sign>' +
        '</xml>'
    return data
}

/**
 * 获取支付sdk配置信息
 * @param appId 小程序ID（应用的id）
 * @param prepayId 预支付的id
 * @returns {{appId: *, nonceStr: *, package: string, signType: string, timeStamp: *}}
 */
let getPayParams = function (appId, prepayId) {
    let nonceStr = util.createNonceStr()
    let package = 'prepay_id=' + prepayId
    let timeStamp = util.createTimeStamp()
    let params = {
        appId,
        nonceStr,
        package,
        signType: 'MD5',
        timeStamp
    }
    let paySign = util.getSign(params, config.key)
    params.paySign = paySign
    return params
}

/**
 * 云函数入口函数
 * @param event
 * @param context
 * @returns {Promise}
 */
exports.main = async (event, context) => {
    const wxContext = cloud.getWXContext()
    // 获取用户的openId
    const openId = wxContext.OPENID
    // 获取用户端传递过来的金额参数
    let totalFee = event.totalFee
    // 解构配置信息
    let { appId, attach, mchId, key, appSecret, body, ip, notifyUrl } = config
    // 生成随机数
    let noceStr = util.createNonceStr()
    // 生成小程序云的交易订单号
    let tradeId = util.getTradeId()
    // 生成支付签名
    let sign = getPrePaySign(appId, attach, body, openId, totalFee, notifyUrl, ip, noceStr, tradeId )
    // 拼接支付下单接口需要的xml数据
    let sendData = wxSendData(appId, attach, body, openId, totalFee, notifyUrl, ip, noceStr, tradeId, sign)

    console.log('sendData =======>', sendData)

    return new Promise((resolve, reject) => {
        let url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
        request({
            url,
            method: 'POST',
            body: sendData
        }, function (err, response, body) {
            if (err) {
                reject(err)
            } else {
                xml.parseString(body.toString('utf-8'), (error, res) => {
                    // 获取xml根对象
                    let data = res.xml
                    console.log('data =======>', data)
                    if (data.return_code[0] == 'SUCCESS' && data.result_code[0] == 'SUCCESS') {
                        // 获取预支付id
                        let prepay_id = data.prepay_id[0]
                        // 生成小程序支付的SDK配置信息
                        let parResult = getPayParams(appId, prepay_id)
                        resolve(parResult)
                    } else {
                        let msg = data.return_msg || data.err_code_des || data.errorMessage
                        reject(msg)
                    }
                })
            }
        })
    })
}